home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / TCL1 / JOHNLOVE / C_SOURCE / CMETER.C < prev    next >
Text File  |  1992-02-22  |  11KB  |  425 lines

  1. /********************************************************************
  2.  "CMeter.c"
  3.  
  4.  by:                            Walt Davis [MacTutor, September 1991]
  5.  
  6.  converted to "C" & OOP by:        John A. Love, III
  7.                                  using Symantec's "THINK C", v 5.0.1
  8.  ********************************************************************/
  9.  
  10.  
  11.  
  12.  
  13. #include <CDecorator.h>
  14. #include <CDesktop.h>
  15. #include <CWindow.h>
  16. #include <TBUtilities.h>
  17.  
  18. #include "CmyGlobals.h"
  19. #include "CmyMisc.h"
  20. #include "CMeter.h"
  21.  
  22.  
  23. extern CDesktop        *gDesktop;
  24. extern CDecorator    *gDecorator;
  25.  
  26.  
  27.  
  28. void    CMeter::IMeter (short WINDid, LongFunc calculateProgress,
  29.                         Str255 bannerStr, short maxSteps,
  30.                         CApplication *itsSupervisor)    {
  31.  
  32.         CMeterMainPane        *mainMeterPane = nil;
  33.         short                windowTooSmall = -10000, deltaH, deltaV;
  34.         // Frame assumes portRect = 292 X 60.  Will be adjusted on the fly:
  35.         Rect                progressR = {22, 16, 22+16, 16+260};
  36.         LongRect            enclRect;
  37.         Rect                enclR, dNewBarSize;
  38.         CProgressBorder        *roundRect = nil;
  39.  
  40.     
  41.     CDocument::IDocument(itsSupervisor, false);
  42.  
  43.     itsWindow = new (CWindow);
  44.     itsWindow->IWindow (WINDid, true /* floating */, gDesktop, this);
  45.     
  46.     // First sub-view:
  47.     mainMeterPane = new (CMeterMainPane);
  48.     mainMeterPane->IPane(
  49.                           itsWindow,
  50.                           this,
  51.                           0, 0, 0, 0,
  52.                           sizELASTIC, sizELASTIC
  53.                         );
  54.     mainMeterPane->FitToEnclosure(true, true);
  55.     itsMainPane = mainMeterPane;
  56.     ;
  57.     CopyPString(bannerStr, mainMeterPane->mTitle);
  58.     calc = calculateProgress;            /* Used by CMakingProgress::Calculate */
  59.     
  60.     // Second sub-view <instance variable in CMeter>:
  61.     meterProgressBar = new (CProgressBar);
  62.     meterProgressBar->IPane(mainMeterPane, this, 0, 0, 0, 0, sizELASTIC, sizELASTIC);
  63.     meterProgressBar->FitToEnclosure(true, true);    
  64.     
  65.     // Sub-view's border:
  66.     roundRect = new (CProgressBorder);
  67.     roundRect->IPaneBorder(kBorderRoundRect);
  68.     meterProgressBar->SetBorder(roundRect);
  69.     
  70.     // Adjust frame size on the fly:
  71.     meterProgressBar->GetFrame(&enclRect);
  72.     /* Default value of CView::usingLongCoord = false,
  73.     ** so the frame is already in QuickDraw coordinates:
  74.     ** meterProgressBar->FrameToQDR(&enclRect, &enclR);    */
  75.     LongToQDRect(&enclRect, &enclR);
  76.  
  77.     deltaH = enclR.right  - (progressR.right  + progressR.left);
  78.     deltaV = enclR.bottom - (progressR.bottom + progressR.top );
  79.     
  80.     if (deltaH < 0 || deltaV < 0)    Failure(windowTooSmall, kSilentErr);
  81.     else    {
  82.     
  83.         deltaV = (deltaV % 16) / 2;
  84.         deltaH = (deltaH % 10) / 2;
  85.     
  86.         SetRect(
  87.                  &dNewBarSize,
  88.                  progressR.left    + deltaH,
  89.                  progressR.top    + deltaV,
  90.                  -(progressR.left + deltaH),
  91.                  -(progressR.top  + deltaV)
  92.                );
  93.         /* ChangeSize still maintains topLeft of frame = {0, 0}.
  94.         ** However, pane's {vOrigin, hOrigin} = - dNewBarSize.topLeft. */
  95.         meterProgressBar->ChangeSize(&dNewBarSize, false /* do NOT redraw */);
  96.     
  97.         /* Another sub-view <second instance variable in CMeter>:
  98.         ** Note that this overlaps exactly its enclosure because
  99.         ** the enclosure draws the oval frame border and the tick
  100.         ** marks, whereas the sub-view draws the moving progress. */
  101.         
  102.         progressO = new (CMakingProgress);
  103.         progressO->IPane(meterProgressBar, this, 0, 0, 0, 0, sizELASTIC, sizELASTIC);
  104.         progressO->FitToEnclosure(true, true);
  105.         progressO->start = false;
  106.         progressO->maxSteps = maxSteps;
  107.         progressO->currStep = 0;
  108.         itsGopher = progressO;
  109.     
  110.         /* System 7 WIND resource automatically centers: */
  111.         if ( !WINDResourceHasSystem7Field(itsWindow) )        {
  112.         
  113.                 short    saveProcID = itsWindow->procID;
  114.                 
  115.                 
  116.             itsWindow->SetModal(false);
  117.             // Gotta do this kludge because CenterWindow tests isModal
  118.             // AND the window's procID:
  119.             itsWindow->procID = 0;
  120.             gDecorator->CenterWindow(itsWindow);
  121.             itsWindow->procID = saveProcID;
  122.         }
  123.         
  124.     }    /* Window big enough */
  125.  
  126. }    /* CMeter::IMeter */
  127.  
  128.  
  129.  
  130. void    CMeterMainPane::Draw (Rect *area)    {
  131.  
  132.         CWindow        *myWindow;
  133.         CMeter        *mySupervisingDoc;
  134.         
  135.         PenState    pnState;
  136.         RGBColor    foreColor,
  137.                     myRed    = {65535,       0,      0},
  138.                     myBlue   = {    0,       0, 65535};
  139.         LongRect    windRect, barRect;
  140.         Rect        windR, box;
  141.         short        stringLen;
  142.         
  143.     myWindow = GetWindow();
  144.     myWindow->GetInterior(&windRect);
  145.     LongToQDRect(&windRect, &windR);
  146.     EraseRect(&windR);
  147.  
  148.     mySupervisingDoc = (CMeter*) GetSupervisor();
  149.     mySupervisingDoc->meterProgressBar->GetFrame(&barRect);
  150.     /* Once again, we are NOT using long coordinates.
  151.     ** But, we ARE drawing in meterProgressBar's window ... */
  152.     mySupervisingDoc->meterProgressBar->FrameToWindR(&barRect, &box);
  153.  
  154.     GetPenState(&pnState);
  155.     if (gSystem.hasColorQD)        GetForeColor(&foreColor);
  156.  
  157.     PenNormal();
  158.     TextFont(systemFont);
  159.     TextSize(12);
  160.  
  161.     // Draw the "horizontal axis" of the dynamic rect:
  162.     
  163.     if (gSystem.hasColorQD)        RGBForeColor(&myRed);
  164.     MoveTo(box.left - 5, box.bottom + 16);
  165.     DrawString("\p0%");
  166.     MoveTo(box.right - 185, box.bottom + 16);
  167.     DrawString("\pPercent Complete");
  168.     MoveTo(box.right - 20, box.bottom + 16);
  169.     DrawString("\p100%");
  170.         
  171.     // Draw the window's "title":
  172.     
  173.     stringLen = StringWidth(mTitle);
  174.     if (stringLen <= frame.right - frame.left)    {
  175.         if (gSystem.hasColorQD)        RGBForeColor(&myBlue);
  176.         MoveTo(frame.left + (frame.right - frame.left - stringLen) / 2, box.top - 9);
  177.         DrawString(mTitle);
  178.     }
  179.     
  180.     if (gSystem.hasColorQD)        RGBForeColor(&foreColor);
  181.     SetPenState(&pnState);
  182.  
  183. }    /* CMeterMainPane::Draw */
  184.  
  185.  
  186.  
  187. void    CProgressBorder::IPaneBorder (short borderFlags)    {
  188.  
  189.         Rect    roundMargin = {0, 0, 0, 0};        /* Border touches Pane */
  190.  
  191.  
  192.     inherited::IPaneBorder(borderFlags);
  193.     
  194.     SetPenSize(1, 1);
  195.     SetRounding(16, 16);
  196.     SetMargin(&roundMargin);
  197.     
  198. }    /* CProgressBorder::IPaneBorder */
  199.  
  200.  
  201.  
  202. void    CProgressBorder::DrawBorder (Rect *paneFrame)    {
  203.  
  204.         RGBColor    saveColor, myRed = {65535, 0, 0};
  205.         
  206.         
  207.     if (gSystem.hasColorQD)        {
  208.         GetForeColor(&saveColor);
  209.         RGBForeColor(&myRed);
  210.     }
  211.     
  212.     inherited::DrawBorder(paneFrame);
  213.     
  214.     if (gSystem.hasColorQD)        RGBForeColor(&saveColor);
  215.  
  216. }    /* CProgressBorder::DrawBorder */
  217.  
  218.  
  219.  
  220. void    CProgressBar::Draw (Rect *area)    {
  221.  
  222.         /* Where the 5% and 10% graduation marks are placed
  223.         ** given a rect 260 pixels wide by 16 pixels tall.
  224.         ** These are changed on the fly based on frame size: */
  225.         short        fiveSize, fiveStep;        /* 2, 13 */
  226.         short        tenSize , tenStep ;        /* 4, 26 */
  227.         
  228.         PenState    pnState;
  229.         RGBColor    foreColor, backColor,
  230.                     myRed    = {65535,       0,      0},
  231.                     myYellow = {65535, 61612,  1737};
  232.         LongRect    progressRect;
  233.         Rect        box;
  234.         short        pnSize = 1, grad, hDiameter, vDiameter;
  235.         
  236.         
  237.     GetFrame(&progressRect);
  238.     LongToQDRect(&progressRect, &box);
  239.     
  240.     /* We could ignore the top-left coordinate because it's
  241.     ** zero since we are not scrolling the pane.  Let's
  242.     ** leave it be, however, to highlight the math:            */
  243.     fiveSize = (box.bottom - box.top )/8;
  244.     tenSize  = fiveSize * 2;
  245.     fiveStep = (box.right  - box.left)/20;
  246.     tenStep  = fiveStep * 2;
  247.         
  248.     GetPenState(&pnState);
  249.     if (gSystem.hasColorQD)        {
  250.         GetForeColor(&foreColor);
  251.         GetBackColor(&backColor);
  252.         RGBForeColor(&myRed);
  253.         RGBBackColor(&myYellow);
  254.     }
  255.  
  256.     PenNormal();
  257.     PenSize(pnSize, pnSize);
  258.     
  259.     itsBorder->GetRounding(&hDiameter, &vDiameter);
  260.     EraseRoundRect(&box, hDiameter, vDiameter);
  261.     
  262.     // Draw the first 5% graduation mark:
  263.     
  264.     MoveTo(box.left + fiveStep, box.top);
  265.     Line(0, fiveSize);
  266.     MoveTo(box.left + fiveStep, box.bottom);
  267.     Line(0, -fiveSize);
  268.     
  269.     // Draw the remaining graduation Marks:
  270.     
  271.     for (grad = 1; grad <= 9; grad++)    {
  272.         MoveTo(box.left + grad*tenStep, box.top);
  273.         Line(0, tenSize);        /* from top */
  274.         MoveTo(box.left + grad*tenStep, box.bottom);
  275.         Line(0, -tenSize);        /* from bottom */
  276.         
  277.         MoveTo(box.left + grad*tenStep + fiveStep, box.top);
  278.         Line(0, fiveSize);
  279.         MoveTo(box.left + grad*tenStep + fiveStep, box.bottom);
  280.         Line(0, -fiveSize);
  281.     }
  282.     
  283.     if (gSystem.hasColorQD)        {
  284.         RGBForeColor(&foreColor);
  285.         RGBBackColor(&backColor);
  286.     }
  287.     SetPenState(&pnState);
  288.  
  289. }    /* CProgressBar::Draw */
  290.  
  291.  
  292.  
  293. void    CMakingProgress::Draw (Rect *area)        {
  294.  
  295.         CMeter                *mySupervisingDoc;
  296.         CProgressBorder        *myBorder;
  297.         RGBColor            saveColor, myGreen = {0, 65535, 0};
  298.         LongRect            progressBar;
  299.         Rect                progress;
  300.         short                hDiameter, vDiameter;
  301.         long                pDone;
  302.  
  303.  
  304.     if (!start || maxSteps == 0)    return;
  305.     /* _FillRoundRect overwrites the frame for VERY small rectangles: */
  306.     if (currStep < 6)        return;
  307.  
  308.     GetFrame(&progressBar);
  309.     LongToQDRect(&progressBar, &progress);
  310.     
  311.     if (gSystem.hasColorQD)        {
  312.         GetForeColor(&saveColor);
  313.         RGBForeColor(&myGreen);
  314.     }
  315.     
  316.     /* A kludgy way to round-up ... BUT it works !!
  317.     ** ... it sure beats using the full ANSI library
  318.     ** which significantly increases the Project size: */
  319.         
  320.     pDone = ((long)currStep * 10000) / maxSteps;
  321.     if (pDone > ( (( (long)currStep*100 )/maxSteps) * 100 ))    pDone = pDone/100 + 1;
  322.     else                                                        pDone = pDone/100;
  323.     if (pDone > 100)    pDone = 100;
  324.     ;
  325.     progress.right = progress.left +
  326.                      (pDone * (progress.right - progress.left))/100;
  327.     
  328.     mySupervisingDoc = (CMeter*) GetSupervisor();
  329.     myBorder = (CProgressBorder*) ( mySupervisingDoc->meterProgressBar->GetBorder() );
  330.     myBorder->GetRounding(&hDiameter, &vDiameter);
  331.     FillRoundRect(&progress, hDiameter, vDiameter, <Gray);
  332.     
  333.     ValidRect(&progress);        /* No pesky updates !! */
  334.     
  335.     if (gSystem.hasColorQD)        RGBForeColor(&saveColor);
  336.  
  337. }    /* CMakingProgress::Draw */
  338.  
  339.  
  340.  
  341. short    CMakingProgress::Calculate (void)        {
  342. /* The Function passed to IMeter determines the % progress
  343. ** you've made, say in spooling a file to the printer.  Here
  344. ** we need to convert this % to a step number:                */
  345.  
  346.         CMeter        *mySupervisingDoc;
  347.         long        percentProgress;
  348.         
  349.         
  350.     mySupervisingDoc = (CMeter*) GetSupervisor();
  351.     
  352.     percentProgress = (*mySupervisingDoc->calc) ();
  353.     return ( (percentProgress*maxSteps) / 100 );
  354.         
  355. }    /* CMakingProgress::Calculate */
  356.  
  357.  
  358.  
  359. void    CMeter::StartProgress (void)    {
  360.  
  361.  
  362.     progressO->start = true;
  363.  
  364. }    /* StartProgress */
  365.  
  366.  
  367.  
  368. void    CMeter::UpdateProgress (void)    {
  369.         
  370.         short    inStep;                /* Local in case Calculate() moves memory
  371.                                     ** when it calls your passed function = calc. */
  372.         Rect    sliderRect;
  373.         long    finalTicks;
  374.         Str255    complete = "\pTask is complete !!!";
  375.         
  376.         
  377.     inStep = progressO->Calculate();
  378.  
  379.     while (inStep <= progressO->maxSteps)    {
  380.         progressO->currStep = inStep;
  381.         progressO->Draw(&sliderRect);
  382.         inStep = progressO->Calculate();
  383.     }
  384.  
  385.     CopyPString(complete, ( (CMeterMainPane*)itsMainPane )->mTitle);
  386.     EndProgress();
  387.     
  388.     Delay(180, &finalTicks);        /* Ain't she pretty !!! */
  389.     Dispose();
  390.     
  391.     SysBeep(10);
  392.  
  393. }    /* CMeter::UpdateProgress */
  394.  
  395.  
  396.  
  397. void    CMeter::EndProgress (void)    {
  398.  
  399.         LongRect    frameLR;
  400.         Rect        windSR;
  401.         
  402.         
  403.     progressO->start = false;
  404.     progressO->currStep = 0;
  405.  
  406.     itsMainPane->GetFrame(&frameLR);
  407.     itsMainPane->FrameToWindR(&frameLR, &windSR);
  408.     itsMainPane->DrawAll(&windSR);
  409.  
  410. }    /* EndProgress */
  411.  
  412.  
  413.  
  414. void    CMeter::Dispose (void)    {
  415.  
  416.  
  417.     inherited::Dispose();
  418.  
  419. }    /* Dispose */
  420.  
  421.  
  422.  
  423.  
  424. /*    { end file "CMeter.c" }  */
  425.